#include "ModelAlgoManager.h"
#include <QDebug>
#include <QDateTime>
#define XLOG_EN
#ifdef XLOG_EN
#define xLog qDebug() << "[" << __FILE__ << ":" << __LINE__ << ":" << __func__ << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz") << "]"
#else
#define xLog QT_NO_QDEBUG_MACRO()
#endif

ModelAlgoManager::ModelAlgoManager()
{
    m_sptr_model_slices_producer = std::make_shared<ModelSlicesProducer>();
}

ModelAlgoManager::~ModelAlgoManager()
{
    m_sptr_model_slices_producer.reset();
}

void ModelAlgoManager::extractModelContours(bool hasTexture, const QVector<Triangle>& triangles, const QVector<Edge>& edges,
                                            const QVector3D& plane_norm, const QVector3D& u_axis, const QVector3D& v_axis,
                                            float stride, float dithering_factor, float merge_threshold)
{
    if(hasTexture)
        extractContoursWithTexture(triangles, edges, plane_norm, u_axis, v_axis, stride, dithering_factor, merge_threshold);
    else
        extractContoursWithoutTexture(triangles, edges, plane_norm, u_axis, v_axis, stride);
}

void ModelAlgoManager::extractContoursWithoutTexture(const QVector<Triangle>& triangles, const QVector<Edge>& edges,
                                                                                  const QVector3D& plane_norm, const QVector3D& u_axis, const QVector3D& v_axis, float stride)
{
    // QVector3D plane_norm = m_sptr_viewCamera->getEye().normalized();
    // float stride = 1e-3f;
    QVector<float> slice_lambdas;
    xLog << QString("开始切片");
    auto preprocessed_partitions = m_sptr_model_slices_producer->preprocessModelDataAlongDirection(edges, plane_norm);
    xLog << QString("切片进度: 1 / 3");
    m_sptr_model_slices_producer->generateSlicesLambda(preprocessed_partitions, stride, slice_lambdas);
    xLog << QString("切片进度: 2 / 3");
    // QVector3D u_axis = QVector3D::crossProduct(m_sptr_viewCamera->getUp(), plane_norm).normalized();
    // QVector3D v_axis = QVector3D::crossProduct(plane_norm, u_axis).normalized();
    qsizetype numSlices = slice_lambdas.size();
    QVector<QVector<QVector<Vertex>>> resultant_contours(numSlices);
    std::for_each(std::execution::par, resultant_contours.begin(), resultant_contours.end(),
                  [&](auto& slice) {
                      int i = &slice - &resultant_contours[0];
                      QVector<QVector<Vertex>> contours_3d;
                      QVector<Edge> contour_edges;
                      QVector<Triangle> proper_meshes = h0(triangles, plane_norm, slice_lambdas[i]);
                      h1(proper_meshes, plane_norm, slice_lambdas[i], contour_edges);
                      h2(contour_edges, contours_3d);
                      slice = std::move(contours_3d);
                  }
    );
    xLog << QString("切片进度: 3 / 3");
    // emit sendAllContours(ContourProcessing::ContourProcessor::convertToStacksFormation(resultant_contours, u_axis, v_axis), stride, {});
    emit sendProcessedContours(QVector<QVector<Vertex>>{ContourProcessing::ContourProcessor::convertToFlatVertices(resultant_contours).vertices});
    xLog << QString("完成切片");
}

void ModelAlgoManager::extractContoursWithTexture(const QVector<Triangle>& triangles, const QVector<Edge>& edges,
                                                                                    const QVector3D& plane_norm, const QVector3D& u_axis, const QVector3D& v_axis,
                                                                                    float stride, float dithering_factor, float merge_threshold)
{
    // QVector3D plane_norm = m_sptr_viewCamera->getEye().normalized();
    // X
    // float stride = 2.8e-4f;
    // float stride = 1e-4f;
    // float stride = 1e-3f;
    // Y
    // float stride = 8.33e-4f;
    // float stride = 4.165e-4f;
    // float inflation_factor = 0.01f;
    QVector3D centroid = ModelAttributesCalculator::calModelCentroid(triangles);
    // 应用膨胀变换
    auto [inflatedTriangles, inflatedEdges] = job1(
        triangles,
        edges,
        centroid,
        plane_norm,
        dithering_factor); // 过大会导致三角形交叠，导致轮廓异常
    QVector<float> slice_lambdas;
    xLog << QString("开始切片");
    auto preprocessed_partitions = m_sptr_model_slices_producer->preprocessModelDataAlongDirection(inflatedEdges, plane_norm);
    xLog << QString("切片进度: 1 / 6");
    m_sptr_model_slices_producer->generateSlicesLambda(preprocessed_partitions, stride, slice_lambdas);
    QVector<float> slice_intervals(slice_lambdas.size() - 1, stride);
    xLog << QString("切片进度: 2 / 6");
    // generateEdgeDensityJSON(preprocessed_partitions, stride, slice_lambdas.back(), slice_lambdas.front(), "edge_density.json");
    // QVector3D u_axis = QVector3D::crossProduct(m_sptr_viewCamera->getUp(), plane_norm).normalized();
    // QVector3D v_axis = QVector3D::crossProduct(plane_norm, u_axis).normalized();
    const QVector<Triangle>& model_triangles = inflatedTriangles;
    qsizetype numSlices = slice_lambdas.size();
    QVector<QVector<QVector<Vertex>>> resultant_contours(numSlices);
    std::for_each(std::execution::par, resultant_contours.begin(), resultant_contours.end(),
                  [&](auto& slice) {
                      int i = &slice - &resultant_contours[0];
                      QVector<QVector<Vertex>> contours_3d;
                      QVector<Edge> contour_edges;
                      QVector<Triangle> proper_meshes = h0(model_triangles, plane_norm, slice_lambdas[i]);
                      h1(proper_meshes, plane_norm, slice_lambdas[i], contour_edges);
                      h2(contour_edges, contours_3d);
                      slice = std::move(contours_3d);
                  }
    );
    xLog << QString("切片进度: 3 / 6");
    job2(resultant_contours, centroid, plane_norm, dithering_factor);
    xLog << QString("切片进度: 4 / 6");
    ContourProcessing::ContourProcessor processor;
    // TODO(mengjinlang): 使用默认处理参数，是目前可得的最高品质切片，如无必要不修改
    auto processed_contours = processor.processContours(resultant_contours, ContourProcessing::ProcessingParams{});
    xLog << QString("切片进度: 5 / 6");
    job3(processed_contours, plane_norm, slice_intervals, u_axis, v_axis, merge_threshold);
    xLog << QString("切片进度: 6 / 6");
    // emit sendAllContours(ContourProcessing::ContourProcessor::convertToStacksFormation(processed_contours, u_axis, v_axis), stride, slice_intervals);
    emit sendProcessedContours(QVector<QVector<Vertex>>{ContourProcessing::ContourProcessor::convertToFlatVertices(processed_contours).vertices});
    xLog << QString("完成切片");
}
